package com.back.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.back.excepction.BaseException;
import com.back.mapper.UserMapper;
import com.back.model.dto.user.RegisterDTO;
import com.back.model.dto.user.UpdatePasswordDTO;
import com.back.model.dto.user.UserDTO;
import com.back.model.dto.user.UserQueryPageDTO;
import com.back.model.entity.User;
import com.back.model.reslut.PageData;
import com.back.model.vo.UserVO;
import com.back.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
* @author haoshuai
* @description 针对表【user(用户)】的数据库操作Service实现
* @createDate 2024-06-29 15:23:08
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Autowired
    private RedissonClient redissonClient;


    // @Resource
    // private WebSocketServerLogin webSocketServer;

    @Override
    public Boolean register(RegisterDTO registerDTO) {
        if (!registerDTO.getCheckPassWord().equals(registerDTO.getPassWord())) {
            throw new BaseException("两次密码不一致");
        }
        User user = new User();
        BeanUtils.copyProperties(registerDTO,user);
        String  SecurePassword = SaSecureUtil.md5(user.getPassWord() + user.getUserName());
        user.setPassWord(SecurePassword);
        return save(user);
    }

    @Override
    public UserVO login(UserDTO userDTO) {
        // 同设备下线
        String oldtokenValue = StpUtil.getTokenValue();
        log.info("lod tokenValue:{}", oldtokenValue);
        /*//下线操作
        try {
            JacksonUtils.objectToJson(new Object());
        } catch (JsonProcessingException e) {
            throw new BaseException(e.getMessage());
        }
        webSocketServer.sendToOneClient(oldtokenValue,"其他客户端登录");*/

        //登录
        User user = getOne(new QueryWrapper<User>().eq("username", userDTO.getUserName()));
        if (user == null) {
            throw new BaseException("用户名错误");
        }
        // String SecurePassword = user.getPassWord();
        String SecurePassword = SaSecureUtil.md5(user.getPassWord() + user.getUserName());
        if (!SecurePassword.equals(user.getPassWord())) {
            throw new BaseException("密码错误");
        }


        StpUtil.login(user.getId());
        // 数据对象转换
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        userVO.setTokenValue(tokenInfo.getTokenValue());
        userVO.setTokenName(tokenInfo.getTokenName());
        return userVO;
    }

    @Override
    public PageData<UserVO> getPageUser(UserQueryPageDTO userQueryPageDTO) {
        List<UserVO> userVOS = new ArrayList<>();
        PageData<UserVO> pageData = new PageData<>();

        Page<User> page = new Page<>(userQueryPageDTO.getPageNum(), userQueryPageDTO.getPageSize());
        IPage<User> listPage = baseMapper.selectPage(page,new QueryWrapper<>());

        listPage.getRecords().forEach(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user,userVO);
            userVOS.add(userVO);
        });
        pageData.setListData(userVOS);
        pageData.setPageCurrent(listPage.getCurrent());
        pageData.setPageSize(listPage.getSize());
        pageData.setTotal(listPage.getTotal());
        return pageData;
    }

    @Override
    public Boolean updateUserPassword(UpdatePasswordDTO updatePasswordDTO) {
        Integer id = updatePasswordDTO.getId();
        String newPassword = updatePasswordDTO.getNewPassword();
        String checkPassword = updatePasswordDTO.getCheckPassword();

        User user = baseMapper.selectById(id);
        String oldPassword = SaSecureUtil.md5(updatePasswordDTO.getOldPassword() + user.getUserName());
        if (!oldPassword.equals(user.getPassWord())) {
            throw new BaseException("旧密码错误");
        }
        if (!newPassword.equals(checkPassword)) {
            throw new BaseException("两次密码不一致");
        }
        user = new User();
        user.setId(id);
        user.setPassWord(SaSecureUtil.md5(newPassword + user.getUserName()));
        return this.updateById(user);
    }

    @Override
    public Boolean TetstRession() {


       /*
            tryLock方法的三个参数：

            第一个参数（5）：最长等待时间（秒）
            第二个参数（30）：锁自动释放时间（秒）
            第三个参数：时间单位
            看门狗机制：如果不设置第二个参数（或设置为-1），Redisson会自动续期锁有效期
        */

        /*
        方法      	                       行为	                                          适用场景
        lock()	                          死等直到抢到锁                                     必须获得锁的关键操作
        tryLock()	                      立即返回（不等待）	                              非关键操作，失败快速降级
        tryLock(5, TimeUnit.SECONDS)      最多等5秒	                                      平衡等待与响应时间的场景
        tryLock(5, 30, SECONDS)	         等5秒，锁有效期30秒（需手动续期）	                  明确知道业务耗时的场景
         */
        // 只设置等待时间，锁有效期由看门狗自动管理
        // 第一种
        RLock lock = redissonClient.getLock("168"); // 领个锁牌
        boolean isLocked = false;
        try {
            // 最多等5秒，锁有效期30秒（不设置leaseTime会启用看门狗自动续期）
            // isLocked = lock.tryLock(1, TimeUnit.SECONDS);
            isLocked = lock.tryLock();
            if (isLocked) {
                // ▼ 抢到锁后的业务代码 ▼
                log.info("1.执行业务中!!!!");
                try {
                    Thread.sleep(30000);
                } catch (InterruptedException e) {
                    lock.unlock();
                    throw new RuntimeException(e);
                }
            } else {
                throw new BaseException("已经提交请稍后再试");
            }
        }
        // catch (InterruptedException e) {
        //     Thread.currentThread().interrupt();
        // }
        finally {
            // 必须判断当前线程是否持有锁
            if (lock.isHeldByCurrentThread()) {
                log.info("2.释放锁!!!!!!");
                lock.unlock();
            }
        }


        // 第二种
        /*try {
            lock.lock();  // 抢锁（没抢到会一直等）
            // ▼ 这里写你的业务代码 ▼
            log.info("处理业务");
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock(); // 完事儿必须还锁！
            }
        }*/
        return null;
    }


}





